package com.shuaigexue.aicodegenerate.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.shuaigexue.aicodegenerate.annotation.AuthCheck;
import com.shuaigexue.aicodegenerate.common.BaseResponse;
import com.shuaigexue.aicodegenerate.common.DeleteRequest;
import com.shuaigexue.aicodegenerate.common.ResultUtils;
import com.shuaigexue.aicodegenerate.constant.AppConstant;
import com.shuaigexue.aicodegenerate.constant.UserConstant;
import com.shuaigexue.aicodegenerate.entity.User;
import com.shuaigexue.aicodegenerate.exception.BusinessException;
import com.shuaigexue.aicodegenerate.exception.ErrorCode;
import com.shuaigexue.aicodegenerate.exception.ThrowUtils;
import com.shuaigexue.aicodegenerate.model.dto.app.*;
import com.shuaigexue.aicodegenerate.model.enums.CodeGenTypeEnum;
import com.shuaigexue.aicodegenerate.model.vo.AppVO;
import com.shuaigexue.aicodegenerate.service.RandomImageService;
import com.shuaigexue.aicodegenerate.service.UserService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.web.bind.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import com.shuaigexue.aicodegenerate.entity.App;
import com.shuaigexue.aicodegenerate.service.AppService;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

/**
 * 应用 控制层。
 *
 * @author shuaigexue
 */
@RestController
@RequestMapping("/app")
public class AppController {

    @Autowired
    private AppService appService;

    @Resource
    private UserService userService;

    // 注入随机图片服务
    @Resource
    private RandomImageService randomImageService;

    // 添加Logger对象
    private Logger log = LoggerFactory.getLogger(AppController.class);

    /**
     * 添加应用
     * @param appAddRequest
     * @param request
     * @return 添加成功的应用id
     *//*
    @PostMapping("add")
    public BaseResponse<Long> add(@RequestBody AppAddRequest appAddRequest, HttpServletRequest request) {
        ThrowUtils.throwIf(appAddRequest == null, ErrorCode.PARAMS_ERROR);
        // 获取提示词
        String initPrompt = appAddRequest.getInitPrompt();
        ThrowUtils.throwIf(StrUtil.isBlank(initPrompt), ErrorCode.PARAMS_ERROR);

        // 获取当前登陆的用户
        User loginUser = userService.getLoginUser(request);

        // 构建入库对象
        App app = new App();
        BeanUtil.copyProperties(appAddRequest, app);
        app.setUserId(loginUser.getId());

        // 应用名称暂时为initprompt前12位
        app.setAppName(initPrompt.substring(0,Math.min(initPrompt.length(),12)));

        // 暂时设置为多文件生成
        app.setCodeGenType(CodeGenTypeEnum.MULTI_FILE.getValue());

        // 插入数据
        boolean result = appService.save(app);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
        // 返回插入数据id
        return ResultUtils.success(app.getId());
    }*/
    /**
     * 添加应用
     * @param appAddRequest
     * @param request
     * @return 添加成功的应用id
     */
    @PostMapping("add")
    public BaseResponse<Long> add(@RequestBody AppAddRequest appAddRequest, HttpServletRequest request) {
        ThrowUtils.throwIf(appAddRequest == null, ErrorCode.PARAMS_ERROR);
        // 获取提示词
        String initPrompt = appAddRequest.getInitPrompt();
        ThrowUtils.throwIf(StrUtil.isBlank(initPrompt), ErrorCode.PARAMS_ERROR);
        // 获取当前登陆的用户
        User loginUser = userService.getLoginUser(request);
        // 构建入库对象
        App app = new App();
        BeanUtil.copyProperties(appAddRequest, app);
        app.setUserId(loginUser.getId());
        // 应用名称暂时为initprompt前12位
        app.setAppName(initPrompt.substring(0, Math.min(initPrompt.length(), 12)));
        // 暂时设置为多文件生成
        app.setCodeGenType(CodeGenTypeEnum.MULTI_FILE.getValue());

        // ====================== 添加随机封面图功能 ======================
        try {
            // 调用随机图片服务获取封面图URL
            String coverImageUrl = randomImageService.getRandomImageUrl();

            // 如果获取失败，使用默认图片
            if (StrUtil.isBlank(coverImageUrl)) {
                coverImageUrl = "https://example.com/default-cover.jpg";
                log.warn("使用默认封面图: {}", coverImageUrl);
            } else {
                log.info("成功获取随机封面图: {}", coverImageUrl);
            }

            // 设置封面图URL
            app.setCover(coverImageUrl);

        } catch (Exception e) {
            log.error("获取随机封面图失败", e);
            // 即使图片获取失败，也继续创建应用，使用默认图片
            app.setCover("https://example.com/default-cover.jpg");
        }
        // ===============================================================

        // 插入数据
        boolean result = appService.save(app);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
        // 返回插入数据id
        return ResultUtils.success(app.getId());
    }

    /**
     * 更新应用(用户只能修改自己的应用名称)
     * @param appUpdateRequest 更新请求
     * @param request 登录用户
     * @return 更新结果
     */
    @PostMapping("update")
    public BaseResponse<Boolean> updateApp(@RequestBody AppUpdateRequest appUpdateRequest, HttpServletRequest request){
        if(appUpdateRequest == null || appUpdateRequest.getId() == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 获取当前登陆的用户
        User loginUser = userService.getLoginUser(request);
        // 获取应用id
        Long appUpdateRequestId = appUpdateRequest.getId();
        // 判断是否存在
        App oldApp = appService.getById(appUpdateRequestId);
        ThrowUtils.throwIf(oldApp == null, ErrorCode.NOT_FOUND_ERROR);
        // 判断是否为同一用户.仅限本人更新
        if(!oldApp.getUserId().equals(loginUser.getId())){
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
        }
        // 是同一用户
        App app = new App();
        app.setId(appUpdateRequestId);
        app.setAppName(appUpdateRequest.getAppName());
        // 设置编辑时间
        app.setEditTime(LocalDateTime.now());
        // 更新
        boolean result = appService.updateById(app);
        return ResultUtils.success(result);
    }


    /**
     * 删除应用(用户只能删除自己的应用)
     * @param deleteRequest 删除请求
     * @param request 登录用户
     * @return 删除结果
     */
    @PostMapping("delete")
    public BaseResponse<Boolean> deleteApp(@RequestBody DeleteRequest deleteRequest, HttpServletRequest request){
        if(deleteRequest == null || deleteRequest.getId() == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 获取当前登陆用户
        User loginUser = userService.getLoginUser(request);
        // 想要删除的应用id
        Long appId = deleteRequest.getId();
        // 获取应用
        App app = appService.getById(appId);
        // 对比当前应用和登陆用户的 id是否相同
        if(!app.getUserId().equals(loginUser.getId())){
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
        }
        boolean result = appService.removeById(appId);
        return ResultUtils.success(result);
    }

    /**
     * 用户查看应用详情
     * @param id 应用id
     * @return 应用详情
     */
    @GetMapping("/get/vo")
    public BaseResponse<AppVO> getAppVOById(long id) {
        ThrowUtils.throwIf(id <= 0, ErrorCode.PARAMS_ERROR);
        // 查询数据库
        App app = appService.getById(id);
        ThrowUtils.throwIf(app == null, ErrorCode.NOT_FOUND_ERROR);
        return ResultUtils.success(appService.getAppVO(app));
    }


    /**
     * 分页获取当前用户创建的应用列表
     * @param appQueryRequest
     * @param request
     * @return
     */
    @PostMapping("/my/list/page/vo")
    public BaseResponse<Page<AppVO>> listMyAppVOByPage(@RequestBody AppQueryRequest appQueryRequest, HttpServletRequest request) {
        ThrowUtils.throwIf(appQueryRequest == null, ErrorCode.PARAMS_ERROR);
        // 获取当前登陆用户
        User loginUser = userService.getLoginUser(request);
        // 获取前端发送的page参数
        long pageSize = appQueryRequest.getPageSize();
        ThrowUtils.throwIf(pageSize>20, ErrorCode.PARAMS_ERROR,"最多只允许查询20条数据");
        long pageNum = appQueryRequest.getPageNum();
        // 查询当前用户的应用
        appQueryRequest.setUserId(loginUser.getId());
        // 创建查询条件
        QueryWrapper queryWrapper = appService.getQueryWrapper(appQueryRequest);
        // 执行分页查询，获取当前用户的应用列表
        Page<App> appPage = appService.page(new Page<>(pageNum, pageSize), queryWrapper);

        // 封装数据
        Page<AppVO> appVOPage = new Page<>(pageNum, pageSize, appPage.getTotalRow());
        List<AppVO> appVOList = appService.getAppVOList(appPage.getRecords());
        appVOPage.setRecords(appVOList);
        return ResultUtils.success(appVOPage);
    }


    /**
     * 分页获取精选应用列表
     * @param appQueryRequest 查询条件
     * @return 应用列表
     */
    @PostMapping("/good/list/page/vo")
    public BaseResponse<Page<AppVO>> listGoodAppVOByPage(@RequestBody AppQueryRequest appQueryRequest) {
        if(appQueryRequest == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数为空");
        }
        // 限制每页只有20页
        long pageNum = appQueryRequest.getPageNum();
        ThrowUtils.throwIf(pageNum>20, ErrorCode.PARAMS_ERROR,"最多只允许查询20条数据");
        long pageSize = appQueryRequest.getPageSize();

        // 只查询精选的应用
        appQueryRequest.setPriority(AppConstant.GOOD_APP_PRIORITY);
        QueryWrapper queryWrapper = appService.getQueryWrapper(appQueryRequest);
        // 分页查询
        Page<App> appPage = appService.page(Page.of(pageNum, pageSize), queryWrapper);

        // 封装数据
        Page<AppVO> appVOPage = new Page<>(pageNum, pageSize, appPage.getTotalRow());
        List<AppVO> appVOList = appService.getAppVOList(appPage.getRecords());
        appVOPage.setRecords(appVOList);
        return ResultUtils.success(appVOPage);
    }



    /**
     * 管理员删除应用
     * @param deleteRequest 删除请求参数，包含要删除的应用ID
     * @return 删除结果，true表示删除成功，false表示删除失败
     */
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    @PostMapping("/admin/delete")
    public BaseResponse<Boolean> deleteApp(@RequestBody DeleteRequest deleteRequest) {
        // 参数校验：检查删除请求和应用ID是否为空或无效
        if(deleteRequest == null || deleteRequest.getId() <= 0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Long id = deleteRequest.getId();
        // 检查要删除的应用是否存在
        App oldApp = appService.getById(id);
        ThrowUtils.throwIf(oldApp == null, ErrorCode.NOT_FOUND_ERROR);
        // 执行删除操作
        boolean result = appService.removeById(id);
        return ResultUtils.success(result);
    }

    /**
     * 管理员更新应用信息
     * @param appAdminUpdateRequest 管理员更新应用请求参数
     * @return 更新结果，true表示更新成功，false表示更新失败
     */
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    @PostMapping("/admin/update")
    public BaseResponse<Boolean> updateAppByAdmin(@RequestBody AppAdminUpdateRequest appAdminUpdateRequest) {
        // 参数校验：检查更新请求和应用ID是否为空或无效
        if(appAdminUpdateRequest == null || appAdminUpdateRequest.getId() <= 0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Long id = appAdminUpdateRequest.getId();
        // 检查要更新的应用是否存在
        App oldApp = appService.getById(id);
        ThrowUtils.throwIf(oldApp == null, ErrorCode.NOT_FOUND_ERROR);
        // 复制属性并设置编辑时间
        App app = new App();
        BeanUtils.copyProperties(appAdminUpdateRequest, app);
        // 更新编辑时间为当前时间
        app.setEditTime(LocalDateTime.now());
        // 执行更新操作
        boolean result = appService.updateById(app);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
        return ResultUtils.success(result);
    }

    /**
     * 管理员查询应用列表
     * @param appQueryRequest 查询参数
     * @return 应用列表
     */
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    @PostMapping("/admin/list/page/vo")
    public BaseResponse<Page<AppVO>> listAppVOByPageByAdmin(@RequestBody AppQueryRequest appQueryRequest) {
        ThrowUtils.throwIf(appQueryRequest == null, ErrorCode.PARAMS_ERROR);
        long pageNum = appQueryRequest.getPageNum();
        long pageSize = appQueryRequest.getPageSize();
        QueryWrapper queryWrapper = appService.getQueryWrapper(appQueryRequest);
        Page<App> appPage = appService.page(Page.of(pageNum, pageSize), queryWrapper);

        // 封装数据
        Page<AppVO> appVOPage = new Page<>(pageNum, pageSize, appPage.getTotalRow());
        List<AppVO> appVOList = appService.getAppVOList(appPage.getRecords());
        appVOPage.setRecords(appVOList);
        return ResultUtils.success(appVOPage);
    }


    /**
     * 管理员根据 id 获取应用详情
     *
     * @param id 应用 id
     * @return 应用详情
     */
    @GetMapping("/admin/get/vo")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public BaseResponse<AppVO> getAppVOByIdByAdmin(long id) {
        ThrowUtils.throwIf(id <= 0, ErrorCode.PARAMS_ERROR);
        // 查询数据库
        App app = appService.getById(id);
        ThrowUtils.throwIf(app == null, ErrorCode.NOT_FOUND_ERROR);
        // 获取封装类
        return ResultUtils.success(appService.getAppVO(app));
    }

    /**
     * 聊天生成代码
     * @param appId 应用ID
     * @param message 消息
     * @param request 请求
     * @return 生成的代码
     */
    @GetMapping(value = "/chat/gen/code", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<ServerSentEvent<String>> chatToGenCode(@RequestParam Long appId,
                                                       @RequestParam String message,
                                                       HttpServletRequest request) {
        // 参数校验
        ThrowUtils.throwIf(appId == null || appId <= 0, ErrorCode.PARAMS_ERROR, "应用ID无效");
        ThrowUtils.throwIf(StrUtil.isBlank(message), ErrorCode.PARAMS_ERROR, "用户消息不能为空");
        // 获取当前登录用户
        User loginUser = userService.getLoginUser(request);
        // 调用服务生成代码（流式）
        Flux<String> contentFlux = appService.chatToGenCode(appId, message, loginUser);
        // 转换为 ServerSentEvent 格式
        return contentFlux
                .map(chunk -> {
                    // 将内容包装成JSON对象，防止输出内容有空哥前端无法识别
                    Map<String, String> wrapper = Map.of("d", chunk);
                    String jsonData = JSONUtil.toJsonStr(wrapper);
                    // 创建 ServerSentEvent 对象
                    return ServerSentEvent.<String>builder()
                            .data(jsonData)
                            .build();
                })
                // 方便前端判断流是否结束，响应式数据
                .concatWith(Mono.just(
                        // 发送结束事件
                        ServerSentEvent.<String>builder()
                                .event("done")
                                .data("")
                                .build()
                ));
    }

    /**
     * 应用部署
     *
     * @param appDeployRequest 部署请求
     * @param request          请求
     * @return 部署 URL
     */
    @PostMapping("/deploy")
    public BaseResponse<String> deployApp(@RequestBody AppDeployRequest appDeployRequest, HttpServletRequest request) {
        ThrowUtils.throwIf(appDeployRequest == null, ErrorCode.PARAMS_ERROR);
        Long appId = appDeployRequest.getAppId();
        ThrowUtils.throwIf(appId == null || appId <= 0, ErrorCode.PARAMS_ERROR, "应用 ID 不能为空");
        // 获取当前登录用户
        User loginUser = userService.getLoginUser(request);
        // 调用服务部署应用
        String deployUrl = appService.deployApp(appId, loginUser);
        return ResultUtils.success(deployUrl);
    }


    /**
     * 保存应用。
     *
     * @param app 应用
     * @return {@code true} 保存成功，{@code false} 保存失败
     */
    @PostMapping("save")
    public boolean save(@RequestBody App app) {
        return appService.save(app);
    }

    /**
     * 根据主键删除应用。
     *
     * @param id 主键
     * @return {@code true} 删除成功，{@code false} 删除失败
     */
    @DeleteMapping("remove/{id}")
    public boolean remove(@PathVariable Long id) {
        return appService.removeById(id);
    }

    /**
     * 根据主键更新应用。
     *
     * @param app 应用
     * @return {@code true} 更新成功，{@code false} 更新失败
     */
    @PutMapping("update")
    public boolean update(@RequestBody App app) {
        return appService.updateById(app);
    }

    /**
     * 查询所有应用。
     *
     * @return 所有数据
     */
    @GetMapping("list")
    public List<App> list() {
        return appService.list();
    }

    /**
     * 根据主键获取应用。
     *
     * @param id 应用主键
     * @return 应用详情
     */
    @GetMapping("getInfo/{id}")
    public App getInfo(@PathVariable Long id) {
        return appService.getById(id);
    }

    /**
     * 分页查询应用。
     *
     * @param page 分页对象
     * @return 分页对象
     */
    @GetMapping("page")
    public Page<App> page(Page<App> page) {
        return appService.page(page);
    }

}
